/*
 * Copyright (C) 2010 TopCoder Inc., All Rights Reserved.
 */
package com.hercules.xre.protocol.testing.runner;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;

import com.hercules.xre.protocol.testing.ProtocolTestingConnectionManagerException;
import com.hercules.xre.protocol.testing.handlers.TestCaseEventHandler;
import com.hercules.xre.protocol.testing.netty.BaseProtocolTestingConnectionManager;
import com.hercules.xre.protocol.testing.netty.tcp.TCPProtocolTestingConnectionManager;
import com.hercules.xre.protocol.testing.netty.websocket.WebSocketProtocolTestingConnectionManager;

/**
 * <p>
 * The gui for test runner.
 * </p>
 * <p>
 * Thread Safety: it's mutable and not thread safe.
 * </p>
 *
 * @author TCSASSEMBLER
 * @version 1.0
 */
public class TestRunnerGUI extends JFrame {

    /**
     * Represents the line separator.
     */
    private static final String LINE_SEPARATOR = System.getProperty("line.separator");

    /**
     * Represents the background color.
     */
    private static final Color BACKGROUND_COLOR = new Color(255, 249, 219);

    /**
     * Represents the bold font.
     */
    private static final Font BOLD_FONT = new Font(Font.SANS_SERIF, Font.BOLD, 12);

    /**
     * Represents the plain font.
     */
    private static final Font PLAIN_FONT = new Font(Font.SANS_SERIF, Font.PLAIN, 12);

    /**
     * Represents the test server.
     */
    private final TestServer server;

    /**
     * Represents the connected state.
     */
    private boolean connected;

    /**
     * Represents the current section.
     */
    private Section currentSection;

    /**
     * Represents the current test.
     */
    private Test currentTest;

    /**
     * Represents the test sections.
     */
    private List<Section> sections;

    /**
     * Represents the index of current section.
     */
    private int sectionIndex = 0;

    /**
     * Represents the tests for current section.
     */
    private List<Test> tests;

    /**
     * Represents the index of current test.
     */
    private int testIndex = -1;

    /**
     * Represents the test result in report file.
     */
    private SortedMap<String, String> results;

    /**
     * Represents the result file.
     */
    private String resultFile;

    /**
     * Represents the test case event handler.
     */
    private TestCaseEventHandler testCaseEventHandler;

    /**
     * JTextArea for description.
     */
    private JTextArea descriptionArea = new JTextArea();

    /**
     * JLabel for description.
     */
    private JLabel descriptionLabel = new JLabel("Test Section Description:");

    /**
     * JScrollPane for description.
     */
    private JScrollPane descriptionPane = new JScrollPane();

    /**
     * JTextArea for log.
     */
    private JTextArea logArea = new JTextArea();

    /**
     * JLabel for log.
     */
    private JLabel logLabel = new JLabel("Test Log");

    /**
     * JScrollPane for log.
     */
    private JScrollPane logPane = new JScrollPane();

    /**
     * JRadioButton for failed test.
     */
    private JRadioButton failedRadioButton = new JRadioButton("Failed");

    /**
     * JRadioButton for passed test.
     */
    private JRadioButton passedRadioButton = new JRadioButton("Passed");

    /**
     * JRadioButton for skipped test.
     */
    private JRadioButton skippedRadioButton = new JRadioButton("Skipped");

    /**
     * ButtonGroup for test result.
     */
    private ButtonGroup resultButtonGroup = new ButtonGroup();

    /**
     * JButton for prev section.
     */
    private JButton prevSectionButton = new JButton("Prev Section");

    /**
     * JButton for next section.
     */
    private JButton nextSectionButton = new JButton("Next Section");

    /**
     * JButton for prev test.
     */
    private JButton prevTestButton = new JButton("Prev Test");

    /**
     * JButton for next test.
     */
    private JButton nextTestButton = new JButton("Next Test");

    /**
     * JButton for finish.
     */
    private JButton finishButton = new JButton("Finish");

    /**
     * JLabel for connected status.
     */
    private JLabel connectedStatusLabel = new JLabel();

    /**
     * JSeparator. it will separate the buttons for sections and tests.
     */
    private JSeparator separator = new JSeparator();

    /**
     * JLabel for test summary.
     */
    private JLabel summaryLabel = new JLabel();

    /**
     * JLabel for test title.
     */
    private JLabel titleLabel = new JLabel("XRE Receiver Test Suite");

    /**
     * Constructor with port, sections, resultFile and results.
     *
     * @param port the port
     * @param sections the test sections
     * @param resultFile the result file
     * @param results the results in result file
     * @throws IllegalArgumentException if the port is invalid
     * @throws ProtocolTestingConnectionManagerException if any error occurs while creating the server.
     */
    public TestRunnerGUI(String serverType, int port, List<Section> sections, String resultFile, SortedMap<String, String> results)
        throws ProtocolTestingConnectionManagerException {
        BaseProtocolTestingConnectionManager manager;
        if (serverType.equals("websocket")) {
            manager = new WebSocketProtocolTestingConnectionManager(port, null, null);
        } else {
            manager = new TCPProtocolTestingConnectionManager(port, null, null);
        }
        server = new TestServer(manager, this);
        this.sections = sections;
        currentSection = sections.get(0);
        this.tests = currentSection.getTests();
        this.resultFile = resultFile;
        this.results = results;
        initComponents();

    }

    /**
     * Logs the message.
     *
     * @param message the message
     * @return the message with section/test id
     * @throws IOException if i/o error occurs while logging.
     */
    public String logMessage(String message) throws IOException {
        logArea.append(message + LINE_SEPARATOR);
        if (currentSection != null && currentTest != null) {
            return currentSection.getId() + "-" + currentTest.getId() + ":" + message;
        } else {
            return message;
        }
    }

    /**
     * Sets the connected state.
     *
     * @param connected if the client is connected.
     */
    public void setConnected(boolean connected) {
        this.connected = connected;
        connectedStatusLabel.setText("Receiver Status: " + (connected ? "Connected" : "Disconnected"));
    }

    /**
     * Returns the connected state.
     *
     * @return the connected state.
     */
    public boolean isConnected() {
        return connected;
    }

    /**
     * Sets the test case event handler.
     *
     * @param testCaseEventHandler the test case event handler.
     */
    public void setTestCaseEventHandler(TestCaseEventHandler testCaseEventHandler) {
        this.testCaseEventHandler = testCaseEventHandler;
    }

    /**
     * Gets the configuration value from the arguments.
     *
     * @param arguments the arguments
     * @param key the configuration key
     * @param defaultValue the default value
     * @return the configuration value
     */
    private static String getConfiguration(List<String> arguments, String key, String defaultValue) {
        String value = defaultValue;
        for (int i = 0; i < arguments.size(); i++) {
            if (key.equals(arguments.get(i))) {
                if (i + 1 == arguments.size()) {
                    printUsage();
                }
                value = arguments.get(i + 1);
                arguments.remove(i);
                arguments.remove(i);
                break;
            }
        }
        return value;
    }

    /**
     * Parses the string to integer.
     *
     * @param value the string value
     * @return the int value
     */
    private static int getInteger(String value) {
        int intValue = 0;
        try {
            intValue = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            printUsage();
        }
        return intValue;
    }

    /**
     * Creates the section with sections properties, section id and tests.
     *
     * @param properties the sections properties
     * @param sectionId the section id
     * @param tests the tests for the section
     * @return the created section
     */
    private static Section createSection(Properties properties, String sectionId, List<Test> tests) {
        Section section = new Section();
        section.setId(sectionId);
        section.setDescription(properties.getProperty(sectionId + ".description"));
        section.setSummary(properties.getProperty(sectionId + ".summary"));
        section.setTests(tests);
        return section;
    }

    /**
     * Creates the test with tests properties, section id, test id and result.
     *
     * @param properties the sections/tests properties
     * @param sectionId the section id
     * @param testId the test id
     * @param result the test result
     * @return the created result
     */
    private static Test createTest(Properties properties, String sectionId, int testId, String result) {
        Test test = new Test();
        test.setId(testId);
        test.setPath(getValue(properties, sectionId + "." + testId + ".path"));
        test.setDescription(getValue(properties, sectionId + "." + testId + ".description"));
        test.setSummary(getValue(properties, sectionId + "." + testId + ".summary"));
        if (result == null) {
            test.setResult(TestResult.SKIPPED);
        } else {
            test.setResult(TestResult.valueOf(result));
        }
        return test;
    }

    /**
     * Exits with the error message.
     *
     * @param message the message
     */
    private static void exitWithErrorMessage(String message) {
        System.err.println(message);
        System.exit(1);
    }

    /**
     * Gets the value from properties.
     *
     * @param properties the properties
     * @param key the property key
     * @return the property value
     */
    private static String getValue(Properties properties, String key) {
        String value = properties.getProperty(key);
        if (value == null) {
            exitWithErrorMessage("Can't find value: " + key);
        }
        return value;
    }

    /**
     * Prints the usage to command and exit.
     */
    private static void printUsage() {
        System.out.println("Usage:(all values are optional)");
        System.out.println("xretest -port 8079 -results <filename> <sectionid>");
        System.out.println("xretest -port 8079 -results <filename> <sectionid>.<testid>");
        System.out.println("xretest -port 8079 -results <filename> <sectionid>.<testid>-<testid>");
        System.out
            .println("xretest -port 8079 -results <filename> <sectionid>.<testid>,<testid>,<testid>-<testid>,<testid>");
        System.exit(1);
    }

    /**
     * Actions for Form Window Closed.
     *
     * @param evt the event
     */
    private void formWindowClosed(WindowEvent evt) {
        finishButtonActionPerformed(null);
    }

    /**
     * This method is called from within the constructor to initialize the form.
     */
    private void initComponents() {
        resultButtonGroup.add(passedRadioButton);
        resultButtonGroup.add(failedRadioButton);
        resultButtonGroup.add(skippedRadioButton);

        passedRadioButton.setFont(PLAIN_FONT);
        failedRadioButton.setFont(PLAIN_FONT);
        skippedRadioButton.setFont(PLAIN_FONT);
        titleLabel.setFont(BOLD_FONT);
        connectedStatusLabel.setFont(PLAIN_FONT);
        summaryLabel.setFont(PLAIN_FONT);
        descriptionLabel.setFont(PLAIN_FONT);
        nextSectionButton.setFont(PLAIN_FONT);
        prevSectionButton.setFont(PLAIN_FONT);
        nextTestButton.setFont(PLAIN_FONT);
        prevTestButton.setFont(PLAIN_FONT);
        finishButton.setFont(PLAIN_FONT);

        setTitle("XRE Receiver Test Suite");
        setBackground(new Color(255, 153, 0));
        setMinimumSize(new Dimension(798, 550));
        addWindowListener(new WindowAdapter() {
            /**
             * Windows closing event handler.
             *
             * @param evt the windows event
             */
            public void windowClosing(WindowEvent evt) {
                formWindowClosed(evt);
            }
        });

        setConnected(false);

        summaryLabel.setText("Test Section Summary: " + currentSection.getSummary());

        descriptionArea.setColumns(20);
        descriptionArea.setEditable(false);
        descriptionArea.setRows(5);
        descriptionArea.setDisabledTextColor(Color.BLACK);
        descriptionArea.setEnabled(false);
        descriptionPane.setViewportView(descriptionArea);
        descriptionArea.setText(currentSection.getDescription().replace("\\n", LINE_SEPARATOR));

        prevTestButton.addActionListener(new ActionListener() {
            /**
             * Action Performed event handler.
             *
             * @param evt the action event
             */
            public void actionPerformed(ActionEvent evt) {
                testButtonActionPerformed(evt);
            }
        });

        nextTestButton.addActionListener(new ActionListener() {
            /**
             * Action Performed event handler.
             *
             * @param evt the action event
             */
            public void actionPerformed(ActionEvent evt) {
                testButtonActionPerformed(evt);
            }
        });

        prevSectionButton.addActionListener(new ActionListener() {
            /**
             * Action Performed event handler.
             *
             * @param evt the action event
             */
            public void actionPerformed(ActionEvent evt) {
                sectionButtonActionPerformed(evt);
            }
        });

        nextSectionButton.addActionListener(new ActionListener() {
            /**
             * Action Performed event handler.
             *
             * @param evt the action event
             */
            public void actionPerformed(ActionEvent evt) {
                sectionButtonActionPerformed(evt);
            }
        });

        finishButton.addActionListener(new ActionListener() {
            /**
             * Action Performed event handler.
             *
             * @param evt the action event
             */
            public void actionPerformed(ActionEvent evt) {
                finishButtonActionPerformed(evt);
            }
        });

        separator.setOrientation(SwingConstants.VERTICAL);

        logLabel.setVisible(false);

        logPane.setVisible(false);

        logArea.setColumns(20);
        logArea.setEditable(false);
        logArea.setRows(5);
        logArea.setDisabledTextColor(new Color(0, 0, 0));
        logPane.setViewportView(logArea);

        ActionListener radioButtonListener = new ActionListener() {
            /**
             * Action Performed event handler.
             *
             * @param evt the action event
             */
            public void actionPerformed(ActionEvent evt) {
                radioButtonActionPerformed(evt);
            }
        };
        passedRadioButton.setVisible(false);
        passedRadioButton.setBackground(BACKGROUND_COLOR);
        passedRadioButton.addActionListener(radioButtonListener);

        failedRadioButton.setVisible(false);
        failedRadioButton.setBackground(BACKGROUND_COLOR);
        failedRadioButton.addActionListener(radioButtonListener);

        skippedRadioButton.setVisible(false);
        skippedRadioButton.setBackground(BACKGROUND_COLOR);
        skippedRadioButton.addActionListener(radioButtonListener);

        GroupLayout layout = new GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                layout.createSequentialGroup().addContainerGap().addGroup(
                        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(
                                skippedRadioButton).addComponent(failedRadioButton).addComponent(passedRadioButton)
                                .addComponent(descriptionPane, javax.swing.GroupLayout.DEFAULT_SIZE, 778,
                                        Short.MAX_VALUE).addComponent(titleLabel).addComponent(connectedStatusLabel)
                                .addComponent(summaryLabel).addComponent(descriptionLabel).addGroup(
                                        layout.createSequentialGroup().addComponent(prevTestButton).addPreferredGap(
                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(
                                                nextTestButton).addGap(12, 12, 12).addComponent(separator,
                                                javax.swing.GroupLayout.PREFERRED_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.PREFERRED_SIZE).addPreferredGap(
                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(
                                                prevSectionButton).addPreferredGap(
                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(
                                                nextSectionButton).addPreferredGap(
                                                javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(
                                                finishButton)).addComponent(logPane,
                                        javax.swing.GroupLayout.DEFAULT_SIZE, 778, Short.MAX_VALUE).addComponent(
                                        logLabel)).addContainerGap()));
        layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup(
                layout.createSequentialGroup().addContainerGap().addComponent(titleLabel).addPreferredGap(
                        javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(connectedStatusLabel).addGap(
                        18, 18, 18).addComponent(summaryLabel).addGap(18, 18, 18).addComponent(descriptionLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(
                                descriptionPane, javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(logLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(logPane,
                                javax.swing.GroupLayout.PREFERRED_SIZE, 122, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(
                                passedRadioButton).addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(failedRadioButton).addPreferredGap(
                                javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(skippedRadioButton)
                        .addGap(6, 6, 6).addGroup(
                                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                        .addComponent(separator).addComponent(prevTestButton,
                                                javax.swing.GroupLayout.Alignment.TRAILING,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent(
                                                nextTestButton, javax.swing.GroupLayout.Alignment.TRAILING,
                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addGroup(
                                                javax.swing.GroupLayout.Alignment.TRAILING,
                                                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                                        .addComponent(prevSectionButton,
                                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                                        .addComponent(nextSectionButton,
                                                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                                                javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                                        .addComponent(finishButton))).addContainerGap(22,
                                Short.MAX_VALUE)));
        getContentPane().setBackground(BACKGROUND_COLOR);
        updateSectionButtonState();
        updateTestButtonState();
        pack();
    }

    /**
     * Actions for radio button selected.
     *
     * @param evt the event
     */
    private void radioButtonActionPerformed(ActionEvent evt) {
        if (evt.getSource() == passedRadioButton) {
            passedRadioButton.setSelected(true);
            currentTest.setResult(TestResult.PASSED);
        } else if (evt.getSource() == failedRadioButton) {
            failedRadioButton.setSelected(true);
            currentTest.setResult(TestResult.FAILED);
        } else {
            skippedRadioButton.setSelected(true);
            currentTest.setResult(TestResult.SKIPPED);
        }
    }

    /**
     * Actions for section button clicked.
     *
     * @param evt the event
     */
    private void sectionButtonActionPerformed(ActionEvent evt) {
        if (evt.getSource() == nextSectionButton) {
            currentSection = sections.get(++sectionIndex);
        } else {
            currentSection = sections.get(--sectionIndex);
        }
        testIndex = -1;
        tests = currentSection.getTests();
        updateSectionButtonState();
        updateTestButtonState();
        logLabel.setVisible(false);
        logPane.setVisible(false);
        skippedRadioButton.setVisible(false);
        passedRadioButton.setVisible(false);
        failedRadioButton.setVisible(false);
        summaryLabel.setText("Test Section Summary: " + currentSection.getSummary());
        descriptionLabel.setText("Test Section Description:");
        descriptionArea.setText(currentSection.getDescription().replace("\\n", LINE_SEPARATOR));
    }

    /**
     * Actions for test button clicked.
     *
     * @param evt the event.
     */
    private void testButtonActionPerformed(ActionEvent evt) {
        if (evt.getSource() == nextTestButton) {
            currentTest = tests.get(++testIndex);
        } else {
            currentTest = tests.get(--testIndex);
        }
        updateTestButtonState();
        logArea.setText("");
        try {
            logLabel.setVisible(true);
            logPane.setVisible(true);
            summaryLabel.setText("Test Summary: " + currentTest.getSummary());
            descriptionLabel.setText("Test Description:");
            descriptionArea.setText(currentTest.getDescription().replace("\\n", LINE_SEPARATOR));
            skippedRadioButton.setVisible(true);
            passedRadioButton.setVisible(true);
            failedRadioButton.setVisible(true);
            switch (currentTest.getResult()) {
            case SKIPPED:
                skippedRadioButton.setSelected(true);
                break;
            case PASSED:
                passedRadioButton.setSelected(true);
                break;
            case FAILED:
                failedRadioButton.setSelected(true);
                break;
            default:
                break;
            }
            server.updateCommandsFile(currentTest.getPath());
            if (connected) {
                server.restartClient();
            }
        } catch (ProtocolTestingConnectionManagerException e) {
            showError(e.getMessage());
        }
    }

    /**
     * Actions for finish button clicked.
     *
     * @param evt the event.
     */
    private void finishButtonActionPerformed(ActionEvent evt) {
        testCaseEventHandler.closeReportFile();
        for (Section section : sections) {
            for (Test test : section.getTests()) {
                results.put(section.getId() + "-" + test.getId(), test.getResult().toString());
            }
        }
        PrintWriter writer = null;
        try {
            writer = new PrintWriter(resultFile.replace("<datetimestamp>", new SimpleDateFormat(
                    "yyyy-MM-dd'T'HH-mm-ss.SSS").format(new Date())));
            String sectionId = null;
            for (Entry<String, String> entry : results.entrySet()) {
                String[] ids = entry.getKey().split("-");
                String result = entry.getValue();
                if (!ids[0].equals(sectionId)) {
                    sectionId = ids[0];
                    writer.println("SectionId:" + sectionId);
                }
                writer.println("TestId:" + ids[1] + " Result:" + result);
            }
            writer.close();
            if (connected) {
                server.shutdownClient();
            }
            server.dispose();
        } catch (ProtocolTestingConnectionManagerException e) {
            exitWithErrorMessage(e.getMessage());
        } catch (IOException e) {
            exitWithErrorMessage(e.getMessage());
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
        System.exit(0);
    }

    /**
     * Show error message in message dialog.
     *
     * @param message the message
     */
    private void showError(String message) {
        JOptionPane.showMessageDialog(this, message, "error", JOptionPane.ERROR_MESSAGE);
    }

    /**
     * Updates section button states.
     */
    private void updateSectionButtonState() {
        prevSectionButton.setEnabled(sectionIndex - 1 >= 0);
        nextSectionButton.setEnabled(sectionIndex + 1 < sections.size());
    }

    /**
     * Updates test button states.
     */
    private void updateTestButtonState() {
        prevTestButton.setEnabled(testIndex - 1 >= 0);
        nextTestButton.setEnabled(testIndex + 1 < tests.size());
    }

    /**
     * Closes the reader.
     *
     * @param reader the reader.
     */
    private static void closeReader(Reader reader) {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                // ignore
            }
        }
    }

    /**
     * Main method for the gui.
     *
     * @param args the command line arguments
     */
    public static void main(final String args[]) {
        List<String> arguments = new ArrayList<String>(Arrays.asList(args));
        final int port = getInteger(getConfiguration(arguments, "-port", "8080"));
        final String resultFileName = getConfiguration(arguments, "-results", "xre_<datetimestamp>.txt");
        final String serverType = getConfiguration(arguments, "-type", "tcp");
        File resultFile = new File(resultFileName);
        final SortedMap<String, String> results = new TreeMap<String, String>();
        if (resultFile.isFile()) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(resultFile));
                String sectionId = null;
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.trim().isEmpty()) {
                        continue;
                    }
                    if (line.startsWith("SectionId:")) {
                        sectionId = line.substring("SectionId:".length());
                    } else {
                        String[] testResults = line.split(" ");
                        String testId = testResults[0].substring("TestId:".length());
                        String testResult = testResults[1].substring("Result:".length());
                        results.put(sectionId + "-" + testId, testResult);
                    }
                }
            } catch (IOException e) {
                exitWithErrorMessage(e.getMessage());
            } finally {
                closeReader(reader);
            }
        }
        Properties properties = new Properties();
        FileReader reader = null;
        try {
            reader = new FileReader(Constants.SECTIONS_FILE);
            properties.load(reader);
        } catch (IOException e) {
            exitWithErrorMessage(e.getMessage());
        } finally {
            closeReader(reader);
        }
        String[] sectionsValue;
        final LinkedList<Section> sections = new LinkedList<Section>();
        if (arguments.isEmpty()) {
            sectionsValue = properties.getProperty("sections").split(",");
            for (String sectionValue : sectionsValue) {
                List<Test> tests = new ArrayList<Test>();
                String[] testsValue = properties.getProperty(sectionValue + ".tests").split(",");
                for (String testValue : testsValue) {
                    tests.add(createTest(properties, sectionValue, Integer.parseInt(testValue), results
                            .get(sectionValue + "-" + testValue)));
                }
                sections.add(createSection(properties, sectionValue, tests));
            }
        } else if (arguments.size() == 1) {
            String sectionArgs = arguments.get(0);
            int index = sectionArgs.indexOf('.');
            if (index == -1) {
                List<Test> tests = new ArrayList<Test>();
                String[] testsValue = properties.getProperty(sectionArgs + ".tests").split(",");
                for (String testValue : testsValue) {
                    tests.add(createTest(properties, sectionArgs, Integer.parseInt(testValue), results.get(sectionArgs
                            + "-" + testValue)));
                }
                sections.add(createSection(properties, sectionArgs, tests));
            } else {
                String sectionValue = sectionArgs.substring(0, index);
                List<Test> tests = new ArrayList<Test>();
                List<Integer> testsValue = new ArrayList<Integer>();
                sectionArgs = sectionArgs.substring(index + 1);
                try {
                    for (String testArgument : sectionArgs.split(",")) {
                        String[] ids = testArgument.split("-");
                        if (ids.length == 1) {
                            testsValue.add(Integer.parseInt(ids[0]));
                        } else if (ids.length == 2) {
                            for (int id = Integer.parseInt(ids[0]); id <= Integer.parseInt(ids[1]); id++) {
                                testsValue.add(id);
                            }
                        } else if (ids.length != 2) {
                            printUsage();
                        }
                    }
                } catch (NumberFormatException e) {
                    printUsage();
                }
                for (int testId : testsValue) {
                    tests.add(createTest(properties, sectionValue, testId, results.get(sectionValue + "-" + testId)));
                }
                sections.add(createSection(properties, sectionValue, tests));
            }
        } else {
            printUsage();
        }
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    new TestRunnerGUI(serverType, port, sections, resultFileName, results).setVisible(true);
                } catch (ProtocolTestingConnectionManagerException e) {
                    exitWithErrorMessage(e.getMessage());
                }
            }
        });
    }
}
